package com.cssl.gulimall.cart.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.cssl.common.constant.ObjectConstant;
import com.cssl.common.constant.auth.AuthConstant;
import com.cssl.common.constant.cart.CartConstant;
import com.cssl.common.to.cart.UserInfoTO;
import com.cssl.common.to.product.SkuInfoTO;
import com.cssl.common.utils.DateUtils;
import com.cssl.common.utils.R;
import com.cssl.common.vo.cart.CartItemVO;
import com.cssl.common.vo.cart.CartVO;
import com.cssl.common.vo.cart.SkuInfoVO;
import com.cssl.gulimall.cart.exception.CartExceptionHandler;
import com.cssl.gulimall.cart.feign.ProductFeignService;
import com.cssl.gulimall.cart.interceptor.CartInterceptor;
import com.cssl.gulimall.cart.service.CartService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;

@Service
public class CartServiceImpl implements CartService {
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private ProductFeignService productFeignService;
    @Autowired
    private Executor executor;

    /**
     * 添加商品到购物车
     */
    @Override
    public CartItemVO addToCart(Long skuId, Integer num) throws ExecutionException, InterruptedException {
        //获取购物车redis操作对象
        BoundHashOperations<String,Object,Object> operations = getCartOps();
        //获取商品
        String cartItemJSONString = (String) operations.get(skuId.toString());
        if(StringUtils.isEmpty(cartItemJSONString)){
            //购物车不存在此商品，需要将当前商品添加到购物车中
            CartItemVO cartItem = new CartItemVO();
            CompletableFuture<Void> getSkuInfoFuture = CompletableFuture.runAsync(()->{
                //远程调用当前商品信息
                R r =productFeignService.getInfo(skuId);
                SkuInfoVO skuInfo = r.getData("skuInfo", new TypeReference<SkuInfoVO>() {
                });
                cartItem.setSkuId(skuInfo.getSkuId());  //商品ID
                cartItem.setTitle(skuInfo.getSkuTitle()); //商品标题
                cartItem.setImage(skuInfo.getSkuDefaultImg()); //商品默认图片
                cartItem.setPrice(skuInfo.getPrice());  //商品单价
                cartItem.setCount(num);   //商品件数
                cartItem.setCheck(true);  //是否选中
            },executor);

            CompletableFuture<Void> getSkuAttrValuesFuture = CompletableFuture.runAsync(()->{
                //远程查询attrName:attrValue信息
                List<String> skuSaleAttrValue = productFeignService.getSkuSaleAttrValues(skuId);
                cartItem.setSkuAttrValues(skuSaleAttrValue);
            },executor);

            CompletableFuture.allOf(getSkuInfoFuture,getSkuAttrValuesFuture).get();
            operations.put(skuId.toString(), JSON.toJSONString(cartItem));
            return cartItem;
        }else {
            //当前购物车已存在此商品，修改当前商品数量
            CartItemVO cartItem = JSON.parseObject(cartItemJSONString, CartItemVO.class);
            cartItem.setCount(cartItem.getCount() + num);
            operations.put(skuId.toString(),JSON.toJSONString(cartItem));
            return cartItem;
        }
    }

    /**
     *根据skuId获取购物车商品信息
     */
    @Override
    public CartItemVO getCartItem(Long skuId) {
        //获取购物车redis操作对象
        BoundHashOperations<String,Object,Object> cartOps = getCartOps();
        String cartItemJSONString = (String) cartOps.get(skuId.toString());
        CartItemVO cartItemVO = JSON.parseObject(cartItemJSONString, CartItemVO.class);
        return cartItemVO;
    }

    /**
     * 获取购物车列表
     */
    @Override
    public CartVO getCart() throws ExecutionException, InterruptedException {
        CartVO cart = new CartVO();
        //获取用户登录信息
        UserInfoTO user = CartInterceptor.threadLocal.get();
        //获取游客购物车
        List<CartItemVO> touristItems = getCartItem(CartConstant.CART_PREFIX + user.getUserKey());
        if(user.getUserId() != null){
            //登录状态
            if(!CollectionUtils.isEmpty(touristItems)){
                //游客购物车非空，需要整合到用户购物车
                for(CartItemVO item : touristItems){
                    //将商品逐个放入用户购物车
                    addToCart(item.getSkuId(),item.getCount());
                }
                //清除游客购物车
                clearCart(CartConstant.CART_PREFIX + user.getUserKey());
            }
            //获取用户购物车(已经合并后的购物车)
            List<CartItemVO> items = getCartItem(CartConstant.CART_PREFIX + user.getUserId());
            cart.setItems(items);
        }else {
            //未登录状态，返回游客购物车
            cart.setItems(touristItems);
        }
        return cart;
    }

    /**
     * 删除购物项
     */
    @Override
    public void deleteIdCartInfo(Integer skuId) {
        BoundHashOperations<String, Object, Object> operations = getCartOps();
        operations.delete(skuId.toString());
    }

    /**
     *改变购物车商品数量
     */
    @Override
    public void changeItemCount(Long skuId, Integer num) {
        //查询购物车商品信息
        CartItemVO cartItem = getCartItem(skuId);
        //修改商品数量
        cartItem.setCount(num);
        //更新至redis
        BoundHashOperations<String,Object,Object> operations = getCartOps();
        operations.put(skuId.toString(),JSONObject.toJSONStringWithDateFormat(cartItem, DateUtils.DATATIMEF_TIME_STR));
    }

    /**
     *更改购物车中商品选中状态
     */
    @Override
    public void checkItem(Long skuId, Integer check) {
        //查询购物车商品信息
        CartItemVO cartItem = getCartItem(skuId);
        //修改商品选中状态
        cartItem.setCheck(ObjectConstant.BooleanIntEnum.YES.getCode().equals(check)?true:false);
        //更新至redis中
        BoundHashOperations<String,Object,Object> operations = getCartOps();
        operations.put(skuId.toString(),JSONObject.toJSONStringWithDateFormat(cartItem,DateUtils.DATATIMEF_TIME_STR));
    }

    /**
     * 情况购物车
     */
    private void clearCart(String cartKey) {
        redisTemplate.delete(cartKey);
    }

    /**
     * 根据购物车的key获取
     */
    private List<CartItemVO> getCartItem(String cartKey) {
        BoundHashOperations<String, Object, Object> operations = redisTemplate.boundHashOps(cartKey);
        List<Object> values = operations.values();
        if(!CollectionUtils.isEmpty(values)){
            //购物车非空，反序列化并封装成集合返回
            return values.stream().map(jsonString-> JSONObject.parseObject((String)jsonString,CartItemVO.class))
                    .collect(Collectors.toList());
        }
        return null;
    }

    /**
     * 根据用户信息获取到购物车redis操作对象
     */
    private BoundHashOperations<String,Object,Object> getCartOps(){
        //获取用户登录信息
        UserInfoTO user = CartInterceptor.threadLocal.get();
        String cartKey = "";
        if(user.getUserId() != null){
            //登录态，使用用户购物车
            cartKey = CartConstant.CART_PREFIX + user.getUserId();
        }else {
            //非登录态，使用游客购物车
            cartKey = CartConstant.CART_PREFIX + user.getUserKey();
        }
        //绑定购物车的key操作redis
        BoundHashOperations<String, Object, Object> operations = redisTemplate.boundHashOps(cartKey);
        return operations;
    }

    @Override
    public List<CartItemVO> getUserCartItems() {
        UserInfoTO userInfo = CartInterceptor.threadLocal.get();
        if(userInfo.getUserId() == null){
            //未登陆
            return null;
        }else {
            //已登录，查询redis用户购物车
            List<CartItemVO> items = getCartItem(CartConstant.CART_PREFIX + userInfo.getUserId());
            if(CollectionUtils.isEmpty(items)){
                throw new CartExceptionHandler();
            }
            //筛选所有选中的sku
            Map<Long, CartItemVO> itemMap = items.stream().filter(item -> item.getCheck()).
                    collect(Collectors.toMap(CartItemVO::getSkuId, val -> val));
            //远程调用获取最新价格
            Map<Long, BigDecimal> priceMap = productFeignService.getPrice(itemMap.keySet());
            //遍历封装真实价格返回
            return itemMap.entrySet().stream().map(entry->{
                CartItemVO item = entry.getValue();
                item.setPrice(priceMap.get(entry.getKey()));
                return item;
            }).collect(Collectors.toList());
        }

    }
}
